package org.wu.acw.client.ui.provider;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.wu.framework.core.CamelAndUnderLineConverter;
import org.wu.framework.core.NormalUsedString;
import org.wu.framework.core.utils.DataTransformUntil;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.lazy.orm.core.config.LazyOperationAttribute;
import org.wu.framework.lazy.orm.core.config.ReverseEngineering;
import org.wu.framework.lazy.orm.core.config.enums.OrmArchitecture;
import org.wu.framework.lazy.orm.core.config.enums.ProgrammingLanguage;
import org.wu.framework.lazy.orm.core.config.enums.WebArchitecture;
import org.wu.framework.lazy.orm.core.config.prop.LazyDataSourceAttribute;
import org.wu.framework.lazy.orm.core.persistence.reverse.ReverseClassFactory;
import org.wu.framework.lazy.orm.core.persistence.reverse.ReverseClassLazyTableEndpoint;
import org.wu.framework.lazy.orm.core.source.adapter.SourceFactory;
import org.wu.framework.lazy.orm.core.source.mysql.MySQLLazyColumn;
import org.wu.framework.lazy.orm.core.source.mysql.MySQLLazySchemata;
import org.wu.framework.lazy.orm.core.source.mysql.MySQLLazyTableInfo;
import org.wu.framework.lazy.orm.database.lambda.dynamic.LazyDynamicDatasourceAdapter;
import org.wu.framework.lazy.orm.database.lambda.dynamic.toolkit.DynamicLazyDSContextHolder;
import org.wu.framework.lazy.orm.database.lambda.stream.lambda.LazyLambdaStream;
import org.wu.framework.lazy.orm.database.lambda.stream.wrapper.LazyWrappers;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;
import org.wu.framework.web.spring.EasyController;
import org.wu.acw.client.ui.application.command.AcwClientGenJavaAPICommand;
import org.wu.acw.client.ui.application.command.AcwClientLocalGenerateLocalJavaCommand;
import org.wu.acw.client.ui.application.dto.JarDefaultPathDTO;

import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 获取当前服务的数据源
 */
//@ConditionalOnBean(LazyLambdaStream.class)
@Slf4j
@Tag(name = "获取当前服务的数据源")
@EasyController("/v1/api/project/dataSource")
public class CurrentProjectDataSourceProvider {

    private final LazyLambdaStream lazyLambdaStream;
    private final LazyDataSourceAttribute lazyDataSourceAttribute;
    private final LazyDynamicDatasourceAdapter lazyDynamicAdapter;

    private final LazyOperationAttribute lazyOperationAttribute;

    public CurrentProjectDataSourceProvider(LazyLambdaStream lazyLambdaStream,
                                            LazyDataSourceAttribute lazyDataSourceAttribute,
                                            LazyDynamicDatasourceAdapter lazyDynamicAdapter,
                                            LazyOperationAttribute lazyOperationAttribute) {
        this.lazyLambdaStream = lazyLambdaStream;
        this.lazyDataSourceAttribute = lazyDataSourceAttribute;
        this.lazyDynamicAdapter = lazyDynamicAdapter;
        this.lazyOperationAttribute = lazyOperationAttribute;
    }


    @Operation(summary = "获取当前数据源", hidden = true)
    @GetMapping("/findDataSourceList")
    public Result<List<String>> findDataSourceList() {
        return ResultFactory.successOf(lazyDynamicAdapter.getDataSourceMap().keySet().stream().toList());

    }

    @Operation(summary = "获取默认schema", hidden = true)
    @GetMapping("/findDefaultSchema")
    public Result<String> findDefaultSchema() {
        String url = lazyDataSourceAttribute.getUrl();
        return ResultFactory.successOf(SourceFactory.getUrlSchema(url));
    }

    // 获取当前实例对应的schema
    @Operation(summary = "获取当前实例对应的schema", hidden = true)
    @GetMapping("/findSchemaList")
    public Result<List<MySQLLazySchemata>> findSchemaList(@RequestParam("instanceId") String instanceId) {
        // 切换datasource
        DynamicLazyDSContextHolder.switchDatasource(instanceId);
        try {
            Collection<MySQLLazySchemata> schematics =
                    lazyLambdaStream.of(MySQLLazySchemata.class).selectList(null);
            return ResultFactory.successOf(schematics.stream().toList());
        } catch (Exception e) {
            e.printStackTrace();
            return ResultFactory.errorOf(e);
        } finally {
            DynamicLazyDSContextHolder.clear();
        }
    }

    // 获取表集合
    @Operation(summary = "获取表集合", hidden = true)
    @GetMapping("/findTableList")
    public Result<List<MySQLLazyTableInfo>> findTableList(@RequestParam("instanceId") String instanceId, @RequestParam("schema") String schema) {
        // 切换datasource
        DynamicLazyDSContextHolder.switchDatasource(instanceId);
        try {
            List<MySQLLazyTableInfo> lazyTableInfos = lazyLambdaStream.selectList(LazyWrappers.<MySQLLazyTableInfo>lambdaWrapper()
                    .eq(MySQLLazyTableInfo::getTableSchema, schema)
            );
            return ResultFactory.successOf(lazyTableInfos);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultFactory.errorOf(e);
        } finally {
            DynamicLazyDSContextHolder.clear();
        }
    }

    // 获取字段集合
    @Operation(summary = "获取字段集合", hidden = true)
    @GetMapping("/findColumnList")
    public Result<List<MySQLLazyColumn>> findColumnList(@RequestParam("instanceId") String instanceId,
                                                   @RequestParam("schema") String schema,
                                                   @RequestParam("tableNameList") List<String> tableNameList) {
        // 切换datasource
        DynamicLazyDSContextHolder.switchDatasource(instanceId);
        try {
            List<MySQLLazyColumn> lazyColumnList = lazyLambdaStream
                    .selectList(LazyWrappers.<MySQLLazyColumn>lambdaWrapper()
                            .eq(MySQLLazyColumn::getTableSchema, schema)
                            .in(MySQLLazyColumn::getTableName, tableNameList)
                    );
            return ResultFactory.successOf(lazyColumnList);
        } catch (
                Exception e) {
            e.printStackTrace();
            return ResultFactory.errorOf(e);
        } finally {
            DynamicLazyDSContextHolder.clear();
        }
    }

    /**
     * 根据表生成本地Java对应代码
     *
     * @param acwClientGenerateLocalJavaCommand 参数
     * @return Result
     */
    @Operation(summary = "根据表生成本地Java对应代码", hidden = true)
    @PostMapping("/clientGenerateLocalJava")
    public Result<?> clientGenerateLocalJava(@RequestBody AcwClientLocalGenerateLocalJavaCommand acwClientGenerateLocalJavaCommand) {
//        根据客户端ID查询客户端信息
        String instanceId = acwClientGenerateLocalJavaCommand.getInstanceId();
        List<String> tableList = acwClientGenerateLocalJavaCommand.getTableList();
        String schemaName = acwClientGenerateLocalJavaCommand.getSchemaName();
        String absolutePath = acwClientGenerateLocalJavaCommand.getAbsolutePath();
        String packageName = acwClientGenerateLocalJavaCommand.getPackageName();
        String prefix = acwClientGenerateLocalJavaCommand.getPrefix();// 文件前缀
        WebArchitecture webArchitecture = acwClientGenerateLocalJavaCommand.getWebArchitecture();
        OrmArchitecture ormArchitecture = acwClientGenerateLocalJavaCommand.getOrmArchitecture();
        boolean enableExport = acwClientGenerateLocalJavaCommand.isEnableExport();
        boolean enableSchema = acwClientGenerateLocalJavaCommand.isEnableSchema();

        // 切换数据源
        DynamicLazyDSContextHolder.switchDatasource(instanceId);
       ReverseEngineering reverseEngineering = lazyOperationAttribute.getReverseEngineering();
        if (!ObjectUtils.isEmpty(absolutePath)) {
            reverseEngineering.setResourceFilePrefix(absolutePath + File.separator);
        }
        if (!ObjectUtils.isEmpty(packageName)) {
            reverseEngineering.setPackageName(packageName);
        }
        if (!ObjectUtils.isEmpty(webArchitecture)) {
            reverseEngineering.setWebArchitecture(webArchitecture);
        }
        if (!ObjectUtils.isEmpty(ormArchitecture)) {
            reverseEngineering.setOrmArchitecture(ormArchitecture);
        }
        if (!ObjectUtils.isEmpty(enableExport)) {
            reverseEngineering.setEnableExport(enableExport);
        }
        reverseEngineering.setEnableSchema(enableSchema);
        try {
            // 查询表信息

            Map<String, MySQLLazyTableInfo> tableInfoMap = lazyLambdaStream
                    .selectList(
                            LazyWrappers.<MySQLLazyTableInfo>lambdaWrapper()
                                    .eq(MySQLLazyTableInfo::getTableSchema, schemaName)
                                    .in(MySQLLazyTableInfo::getTableName, tableList))
                    .stream()
                    .collect(Collectors.toMap(MySQLLazyTableInfo::getTableName, Function.identity(), (A, B) -> A));

            // 查询表字段信息
            Map<String/*表*/, List<MySQLLazyColumn>/*表字段*/> tableColumnMap = lazyLambdaStream.selectList(
                            LazyWrappers.<MySQLLazyColumn>lambdaWrapper()
                                    .eq(MySQLLazyColumn::getTableSchema, schemaName)
                                    .in(MySQLLazyColumn::getTableName, tableList))
                    .stream().collect(Collectors.groupingBy(MySQLLazyColumn::getTableName));

            // 生成数据
            List<AcwClientGenJavaAPICommand> acwClientGenJavaAPICommands = tableColumnMap.entrySet().stream().map(stringListEntry -> {
                String tableName = stringListEntry.getKey();
                List<MySQLLazyColumn> lazyColumnList = stringListEntry.getValue();
                MySQLLazyTableInfo lazyTableInfo = tableInfoMap.get(tableName);
                List<AcwClientGenJavaAPICommand.InnerLazyTableFieldEndpoint> fieldLazyTableFieldEndpointList = lazyColumnList.stream().map(lazyColumn -> {
                    AcwClientGenJavaAPICommand.InnerLazyTableFieldEndpoint fieldEndpoint = new AcwClientGenJavaAPICommand.InnerLazyTableFieldEndpoint();
                    String columnName = lazyColumn.getColumnName();
                    fieldEndpoint.setColumnName(columnName);
                    fieldEndpoint.setName(CamelAndUnderLineConverter.lineToHumpField(columnName));
                    fieldEndpoint.setComment(lazyColumn.getColumnComment());
                    fieldEndpoint.setColumnType(lazyColumn.getColumnType());
                    fieldEndpoint.setDataType(lazyColumn.getDataType());
                    fieldEndpoint.setNotNull(NormalUsedString.NO.equalsIgnoreCase(lazyColumn.getIsNullable()));
                    fieldEndpoint.setDefaultValue(lazyColumn.getColumnDefault());
                    fieldEndpoint.setAlias(columnName);
                    String extra = lazyColumn.getExtra();
                    fieldEndpoint.setExtra(extra);
                    String columnKey = lazyColumn.getColumnKey();
                    fieldEndpoint.setKey("PRI".equals(columnKey));
                    return fieldEndpoint;
                }).collect(Collectors.toList());
                AcwClientGenJavaAPICommand.InnerReverseClassLazyTableEndpoint reverseClassLazyTableEndpoint = new AcwClientGenJavaAPICommand.InnerReverseClassLazyTableEndpoint();
                reverseClassLazyTableEndpoint.setSchema(schemaName);
                reverseClassLazyTableEndpoint.setTableName(tableName);
                if (ObjectUtils.isEmpty(prefix)) {
                    reverseClassLazyTableEndpoint.setClassName(CamelAndUnderLineConverter.lineToHumpClass(tableName));
                } else {
                    reverseClassLazyTableEndpoint.setClassName(CamelAndUnderLineConverter.capitalizeFirstLetter(prefix) + CamelAndUnderLineConverter.lineToHumpClass(tableName));
                }
                reverseClassLazyTableEndpoint.setInLazyTableFieldEndpoints(fieldLazyTableFieldEndpointList);
                // 数据拷贝 否则数据转换有问题
                List<AcwClientGenJavaAPICommand.InnerLazyTableFieldEndpoint> outLazyTableFieldEndpoints =
                        fieldLazyTableFieldEndpointList.stream().map(AcwClientGenJavaAPICommand.InnerLazyTableFieldEndpoint::copy)
                                .toList();
                reverseClassLazyTableEndpoint.setOutLazyTableFieldEndpoints(outLazyTableFieldEndpoints);
                reverseClassLazyTableEndpoint.setModelLazyTableFieldEndpoints(fieldLazyTableFieldEndpointList);
                reverseClassLazyTableEndpoint.setComment(lazyTableInfo.getTableComment());
                reverseClassLazyTableEndpoint.setPackageName(reverseEngineering.getPackageName());

                String entitySuffix = reverseEngineering.getEntitySuffix();
                if (!ObjectUtils.isEmpty(entitySuffix)) {
                    String className = reverseClassLazyTableEndpoint.getClassName();
                    reverseClassLazyTableEndpoint.setClassName(className + entitySuffix);
                }

                AcwClientGenJavaAPICommand acwClientGenJavaAPICommand = new AcwClientGenJavaAPICommand();

                acwClientGenJavaAPICommand.setReverseEngineering(DataTransformUntil.copyBean(reverseEngineering));
                acwClientGenJavaAPICommand.setInnerReverseClassLazyTableEndpoint(reverseClassLazyTableEndpoint);
                return acwClientGenJavaAPICommand;
            }).toList();

//            return acwClientApi.generateLocalJava(acwClientGenJavaAPICommands);
            for (AcwClientGenJavaAPICommand acwClientGenJavaAPICommand : acwClientGenJavaAPICommands) {
                AcwClientGenJavaAPICommand.InnerReverseClassLazyTableEndpoint innerReverseClassLazyTableEndpoint = acwClientGenJavaAPICommand.getInnerReverseClassLazyTableEndpoint();
                ReverseClassLazyTableEndpoint reverseClassLazyTableEndpoint = innerReverseClassLazyTableEndpoint.toReverseClassLazyTableEndpoint();
                if (ProgrammingLanguage.JAVA.equals(acwClientGenerateLocalJavaCommand.getProgrammingLanguage())) {
                    // 创建Java 代码
                    ReverseClassFactory.createJava(reverseClassLazyTableEndpoint, reverseEngineering);
                } else if (ProgrammingLanguage.VUE.equals(acwClientGenerateLocalJavaCommand.getProgrammingLanguage())){
                    // 创建其他语言代码
                    ReverseClassFactory.createVue(reverseClassLazyTableEndpoint, reverseEngineering);
                }else {
                    log.warn("无法执行此语言");
                }
            }
            return ResultFactory.successOf();

        } catch (Exception e) {
            throw e;
        } finally {
            DynamicLazyDSContextHolder.clear();
        }
    }

    /**
     * 获取当前项目默认配置
     *
     * @return Result
     */
    @Operation(summary = "获取当前项目默认配置", hidden = true)
    @GetMapping("/findJarDefault")
    public Result<List<JarDefaultPathDTO>> findJarDefault() {
        // 获取当前项目绝对路径
        String absolutePath = System.getProperty("user.dir");
        System.out.println(absolutePath);

        // 获取当前项目main 方法的包名
        JarDefaultPathDTO jarDefaultPathDTO = new JarDefaultPathDTO();
        jarDefaultPathDTO.setAbsolutePath(absolutePath);
        jarDefaultPathDTO.setPackageName("org.wu.framework.inner.lazy.local.example");

        return ResultFactory.successOf(List.of(jarDefaultPathDTO));

    }
}
